/**
 * @brief MCU 型号规格定义头文件 - GPIO
 * @detail 在此头文件中定义那些与 MCU 内部具体实现有关的定义，不同的 MCU 可能取值范围有所不同。
 * @note 注意: 用户不要包含此头文件！它只由 mcu.h 包含。
 * @author 张勇 41204@qq.com
 * @date 2022-04
 */

#pragma once

#include <stm32f4xx_ll_gpio.h>
#include "mcu.h"

/**
 * @brief GPIO 端口号定义
 */
typedef enum _mcu_gpio_num {
    MCU_GPIO_NUM_PA0 = 0,
    MCU_GPIO_NUM_PA1,
    MCU_GPIO_NUM_PA2,
    MCU_GPIO_NUM_PA3,
    MCU_GPIO_NUM_PA4,
    MCU_GPIO_NUM_PA5,
    MCU_GPIO_NUM_PA6,
    MCU_GPIO_NUM_PA7,
    MCU_GPIO_NUM_PA8,
    MCU_GPIO_NUM_PA9,
    MCU_GPIO_NUM_PA10,
    MCU_GPIO_NUM_PA11,
    MCU_GPIO_NUM_PA12,
    MCU_GPIO_NUM_PA13,
    MCU_GPIO_NUM_PA14,
    MCU_GPIO_NUM_PA15,

    MCU_GPIO_NUM_PB0,
    MCU_GPIO_NUM_PB1,
    MCU_GPIO_NUM_PB2,
    MCU_GPIO_NUM_PB3,
    MCU_GPIO_NUM_PB4,
    MCU_GPIO_NUM_PB5,
    MCU_GPIO_NUM_PB6,
    MCU_GPIO_NUM_PB7,
    MCU_GPIO_NUM_PB8,
    MCU_GPIO_NUM_PB9,
    MCU_GPIO_NUM_PB10,
    MCU_GPIO_NUM_PB11,
    MCU_GPIO_NUM_PB12,
    MCU_GPIO_NUM_PB13,
    MCU_GPIO_NUM_PB14,
    MCU_GPIO_NUM_PB15,

    MCU_GPIO_NUM_PC0,
    MCU_GPIO_NUM_PC1,
    MCU_GPIO_NUM_PC2,
    MCU_GPIO_NUM_PC3,
    MCU_GPIO_NUM_PC4,
    MCU_GPIO_NUM_PC5,
    MCU_GPIO_NUM_PC6,
    MCU_GPIO_NUM_PC7,
    MCU_GPIO_NUM_PC8,
    MCU_GPIO_NUM_PC9,
    MCU_GPIO_NUM_PC10,
    MCU_GPIO_NUM_PC11,
    MCU_GPIO_NUM_PC12,
    MCU_GPIO_NUM_PC13,
    MCU_GPIO_NUM_PC14,
    MCU_GPIO_NUM_PC15,

    MCU_GPIO_NUM_PD0,
    MCU_GPIO_NUM_PD1,
    MCU_GPIO_NUM_PD2,
    MCU_GPIO_NUM_PD3,
    MCU_GPIO_NUM_PD4,
    MCU_GPIO_NUM_PD5,
    MCU_GPIO_NUM_PD6,
    MCU_GPIO_NUM_PD7,
    MCU_GPIO_NUM_PD8,
    MCU_GPIO_NUM_PD9,
    MCU_GPIO_NUM_PD10,
    MCU_GPIO_NUM_PD11,
    MCU_GPIO_NUM_PD12,
    MCU_GPIO_NUM_PD13,
    MCU_GPIO_NUM_PD14,
    MCU_GPIO_NUM_PD15,

    MCU_GPIO_NUM_PE0,
    MCU_GPIO_NUM_PE1,
    MCU_GPIO_NUM_PE2,
    MCU_GPIO_NUM_PE3,
    MCU_GPIO_NUM_PE4,
    MCU_GPIO_NUM_PE5,
    MCU_GPIO_NUM_PE6,
    MCU_GPIO_NUM_PE7,
    MCU_GPIO_NUM_PE8,
    MCU_GPIO_NUM_PE9,
    MCU_GPIO_NUM_PE10,
    MCU_GPIO_NUM_PE11,
    MCU_GPIO_NUM_PE12,
    MCU_GPIO_NUM_PE13,
    MCU_GPIO_NUM_PE14,
    MCU_GPIO_NUM_PE15,

    MCU_GPIO_NUM_PF0,
    MCU_GPIO_NUM_PF1,
    MCU_GPIO_NUM_PF2,
    MCU_GPIO_NUM_PF3,
    MCU_GPIO_NUM_PF4,
    MCU_GPIO_NUM_PF5,
    MCU_GPIO_NUM_PF6,
    MCU_GPIO_NUM_PF7,
    MCU_GPIO_NUM_PF8,
    MCU_GPIO_NUM_PF9,
    MCU_GPIO_NUM_PF10,
    MCU_GPIO_NUM_PF11,
    MCU_GPIO_NUM_PF12,
    MCU_GPIO_NUM_PF13,
    MCU_GPIO_NUM_PF14,
    MCU_GPIO_NUM_PF15,

#ifdef GPIOG
    MCU_GPIO_NUM_PG0,
    MCU_GPIO_NUM_PG1,
    MCU_GPIO_NUM_PG2,
    MCU_GPIO_NUM_PG3,
    MCU_GPIO_NUM_PG4,
    MCU_GPIO_NUM_PG5,
    MCU_GPIO_NUM_PG6,
    MCU_GPIO_NUM_PG7,
    MCU_GPIO_NUM_PG8,
    MCU_GPIO_NUM_PG9,
    MCU_GPIO_NUM_PG10,
    MCU_GPIO_NUM_PG11,
    MCU_GPIO_NUM_PG12,
    MCU_GPIO_NUM_PG13,
    MCU_GPIO_NUM_PG14,
    MCU_GPIO_NUM_PG15,
#endif

#ifdef GPIOH
    MCU_GPIO_NUM_PH0,
    MCU_GPIO_NUM_PH1,
    MCU_GPIO_NUM_PH2,
    MCU_GPIO_NUM_PH3,
    MCU_GPIO_NUM_PH4,
    MCU_GPIO_NUM_PH5,
    MCU_GPIO_NUM_PH6,
    MCU_GPIO_NUM_PH7,
    MCU_GPIO_NUM_PH8,
    MCU_GPIO_NUM_PH9,
    MCU_GPIO_NUM_PH10,
    MCU_GPIO_NUM_PH11,
    MCU_GPIO_NUM_PH12,
    MCU_GPIO_NUM_PH13,
    MCU_GPIO_NUM_PH14,
    MCU_GPIO_NUM_PH15,
#endif

#ifdef GPIOI
    MCU_GPIO_NUM_PI0,
    MCU_GPIO_NUM_PI1,
    MCU_GPIO_NUM_PI2,
    MCU_GPIO_NUM_PI3,
    MCU_GPIO_NUM_PI4,
    MCU_GPIO_NUM_PI5,
    MCU_GPIO_NUM_PI6,
    MCU_GPIO_NUM_PI7,
    MCU_GPIO_NUM_PI8,
    MCU_GPIO_NUM_PI9,
    MCU_GPIO_NUM_PI10,
    MCU_GPIO_NUM_PI11,
    MCU_GPIO_NUM_PI12,
    MCU_GPIO_NUM_PI13,
    MCU_GPIO_NUM_PI14,
    MCU_GPIO_NUM_PI15,
#endif

#ifdef GPIOJ
    MCU_GPIO_NUM_PJ0,
    MCU_GPIO_NUM_PJ1,
    MCU_GPIO_NUM_PJ2,
    MCU_GPIO_NUM_PJ3,
    MCU_GPIO_NUM_PJ4,
    MCU_GPIO_NUM_PJ5,
    MCU_GPIO_NUM_PJ6,
    MCU_GPIO_NUM_PJ7,
    MCU_GPIO_NUM_PJ8,
    MCU_GPIO_NUM_PJ9,
    MCU_GPIO_NUM_PJ10,
    MCU_GPIO_NUM_PJ11,
    MCU_GPIO_NUM_PJ12,
    MCU_GPIO_NUM_PJ13,
    MCU_GPIO_NUM_PJ14,
    MCU_GPIO_NUM_PJ15,
#endif

#ifdef GPIOK
    MCU_GPIO_NUM_PK0,
    MCU_GPIO_NUM_PK1,
    MCU_GPIO_NUM_PK2,
    MCU_GPIO_NUM_PK3,
    MCU_GPIO_NUM_PK4,
    MCU_GPIO_NUM_PK5,
    MCU_GPIO_NUM_PK6,
    MCU_GPIO_NUM_PK7,
    MCU_GPIO_NUM_PK8,
    MCU_GPIO_NUM_PK9,
    MCU_GPIO_NUM_PK10,
    MCU_GPIO_NUM_PK11,
    MCU_GPIO_NUM_PK12,
    MCU_GPIO_NUM_PK13,
    MCU_GPIO_NUM_PK14,
    MCU_GPIO_NUM_PK15,
#endif

    MCU_GPIO_NUM_MAX
} mcu_gpio_num_t;

#ifdef __cplusplus
extern "C" {
#endif

/// @brief 获取 GPIO 引脚对应的 GPIO 端口
GPIO_TypeDef* mcu_gpio_port(mcu_gpio_num_t num);
/// @brief mcu_gpio_num_t 转换为 LL_GPIO_PIN_x
uint32_t mcu_gpio_pin(mcu_gpio_num_t num);
/// @brief 设置 GPIO 引脚复用功能
std_err_t mcu_gpio_pinmux_config(mcu_gpio_num_t num, uint32_t func);
/// @brief GPIO 引脚功能复用关系配置函数类型声明
typedef mcu_gpio_num_t (*mcu_gpio_mux_func_init_t)();

/// @brief GPIO 口初始化配置
std_err_t mcu_gpio_config(mcu_gpio_num_t num, mcu_gpio_mode_t mode);

/// @brief 获取输入电平(如果失败返回 -1)
int8_t    mcu_gpio_read_in(mcu_gpio_num_t num);

/// @brief 设置 GPIO 口输出电平
std_err_t mcu_gpio_write_out(mcu_gpio_num_t num, bool level);
/// @brief GPIO 口输出电平反转
std_err_t mcu_gpio_toggle(mcu_gpio_num_t num);
/// @brief 获取当前 GPIO 口输出的电平(如果失败返回 -1)
int8_t    mcu_gpio_read_out(mcu_gpio_num_t num);

/// @brief GPIO 双向通信输入(如果失败返回 -1)
int8_t    mcu_gpio_bidi_read_in(mcu_gpio_num_t num, mcu_gpio_mode_t in_mode);
/// @brief GPIO 双向通信输出
std_err_t mcu_gpio_bidi_write_out(mcu_gpio_num_t num, mcu_gpio_mode_t out_mode, bool level);

/// @brief GPIO 口对应的 EXTI 中断号
/// @return 返回 <0 时表示此 GPIO 不支持 EXTI 中断
int       mcu_gpio_exti_irqn(mcu_gpio_num_t num);
/// @brief 配置 GPIO EXTI 中断
/// @param trig 触发类型
/// @param opt (可选)额外参数（有些 MCU 支持一些特殊触发功能参数）
std_err_t mcu_gpio_exti_config(mcu_gpio_num_t num, mcu_gpio_intr_type_t trig, void *opt, mcu_isr_t isr, void *isr_cookie);
/// @brief 翻转中断触发(边沿/电平)极性（有些 MCU 不支持双边沿触发，所以需要通过在中断时翻转极性来实现双边沿触发）
std_err_t mcu_gpio_exti_toggle_trig_polarity(mcu_gpio_num_t num);
/// @brief 使能关闭 GPIO EXTI 中断
std_err_t mcu_gpio_exti_enable(mcu_gpio_num_t num, bool enable);
/// 判断 GPIO 口是否产生 EXTI 中断
uint32_t  mcu_gpio_exti_flag(mcu_gpio_num_t num);
/// 清除 GPIO 口对应的 EXTI 中断标志位
std_err_t mcu_gpio_exti_clear(mcu_gpio_num_t num);

/// @brief 定义命名的 GPIO APIs(基本的)
#define GPIO_DEFINE(NAME, PIN) \
	std_err_t GPIO_##NAME##_Config(mcu_gpio_mode_t mode){ return mcu_gpio_config(MCU_GPIO_NUM_##PIN, mode); } \
	int8_t    GPIO_##NAME##_ReadIn(void)          		{ return mcu_gpio_read_in(MCU_GPIO_NUM_##PIN); } \
	std_err_t GPIO_##NAME##_WriteOut(bool x)       		{ return mcu_gpio_write_out(MCU_GPIO_NUM_##PIN, x); } \
	int8_t    GPIO_##NAME##_ReadOut(void)         		{ return mcu_gpio_read_out(MCU_GPIO_NUM_##PIN); } \
	std_err_t GPIO_##NAME##_Toggle(void)               	{ return mcu_gpio_toggle(MCU_GPIO_NUM_##PIN); } \
	std_err_t GPIO_##NAME##_EXTI_Config(mcu_gpio_intr_type_t trig, void *opt, mcu_isr_t isr, void *isr_cookie) { return mcu_gpio_exti_config(MCU_GPIO_NUM_##PIN, trig, opt, isr, isr_cookie); } \
	int       GPIO_##NAME##_EXTI_IRQn(void)            	{ return mcu_gpio_exti_irqn(MCU_GPIO_NUM_##PIN); } \
	std_err_t GPIO_##NAME##_EXTI_ToggleTrigPolarity(void) { return mcu_gpio_exti_toggle_trig_polarity(MCU_GPIO_NUM_##PIN); } \
	std_err_t GPIO_##NAME##_EXTI_Enable(void)         	{ return mcu_gpio_exti_enable(MCU_GPIO_NUM_##PIN, true); } \
	std_err_t GPIO_##NAME##_EXTI_Disable(void)         	{ return mcu_gpio_exti_enable(MCU_GPIO_NUM_##PIN, false); } \
	uint32_t  GPIO_##NAME##_EXTI_Flag(void)            	{ return mcu_gpio_exti_flag(MCU_GPIO_NUM_##PIN); } \
	std_err_t GPIO_##NAME##_EXTI_Clear(void)           	{ return mcu_gpio_exti_clear(MCU_GPIO_NUM_##PIN); }

/// @brief 定义命名的 GPIO APIs(带极性的)
#define GPIO_DEFINE_POLARITY(NAME, PIN, ACTIVE_LEVEL) \
	GPIO_DEFINE(NAME, PIN) \
	std_err_t GPIO_##NAME##_On(void)                   	{ return GPIO_##NAME##_WriteOut(ACTIVE_LEVEL); } \
	std_err_t GPIO_##NAME##_Off(void)                  	{ return GPIO_##NAME##_WriteOut(!ACTIVE_LEVEL); } \
	std_err_t GPIO_##NAME##_Switch(bool on)         	{ return on ? GPIO_##NAME##_On() : GPIO_##NAME##_Off(); } \
	bool      GPIO_##NAME##_IsInOn(void)          		{ return (GPIO_##NAME##_ReadIn() == ACTIVE_LEVEL); } \
	bool      GPIO_##NAME##_IsInOff(void)         		{ return (GPIO_##NAME##_ReadIn() != ACTIVE_LEVEL); } \
	bool      GPIO_##NAME##_IsOutOn(void)         		{ return (GPIO_##NAME##_ReadOut() == ACTIVE_LEVEL); } \
	bool      GPIO_##NAME##_IsOutOff(void)        		{ return (GPIO_##NAME##_ReadOut() != ACTIVE_LEVEL); }

/// @brief 定义命名的 GPIO APIs(双向I/O)
#define GPIO_DEFINE_BIDI(NAME, PIN, INMODE, OUTMODE) \
	int8_t    GPIO_##NAME##_BidiReadIn(void)         	{ return mcu_gpio_bidi_read_in(MCU_GPIO_NUM_##PIN, MCU_GPIO_MODE_##INMODE); } \
	std_err_t GPIO_##NAME##_BidiWriteOut(bool x)        { return mcu_gpio_bidi_write_out(MCU_GPIO_NUM_##PIN, MCU_GPIO_MODE_##OUTMODE, x); }


#ifdef __cplusplus
}
#endif
